/*
 * Copyright (c) 2016-2017 fulihui.com All right reserved
 * Project: information-core-170307
 * File name: ContentVoteServiceContentVoteServiceImpl.java
 */

package com.fulihui.information.service;

import com.fulihui.information.api.ContentVoteService;
import com.fulihui.information.biz.counter.ContentDownVoteTimesOperableCounter;
import com.fulihui.information.biz.counter.ContentUpVoteTimesOperableCounter;
import com.fulihui.information.core.repository.ContentRepository;
import com.fulihui.information.dal.dataobj.InfoUserVoteContent;
import com.fulihui.information.dal.dataobj.InfoUserVoteContentExample;
import com.fulihui.information.dal.dataobj.InfoUserVoteContentKey;
import com.fulihui.information.dal.mapper.InfoUserVoteContentMapper;
import com.fulihui.information.dto.ContentListItemDTO;
import com.fulihui.information.enums.EVoteType;
import com.fulihui.information.model.UserContentOperate;
import com.fulihui.information.request.ContentVoteRequest;
import org.apache.dubbo.config.annotation.Service;
import org.near.servicesupport.error.Errors;
import org.near.servicesupport.result.BaseResult;
import org.near.servicesupport.result.TPageResult;
import org.near.servicesupport.result.TSingleResult;
import org.near.servicesupport.util.ServiceAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.List;
import java.util.stream.Collectors;

import static java.util.Collections.emptyList;
import static org.near.servicesupport.result.ResultBuilder.*;
import static org.springframework.util.CollectionUtils.isEmpty;

/**
 * @author Willard.Hu on 2017/2/21 0021.
 */
@Service(version = "1.0.0")
public class ContentVoteServiceImpl implements ContentVoteService {
    @Autowired
    private InfoUserVoteContentMapper           infoUserVoteContentMapper;
    @Autowired
    private ContentRepository                   contentRepository;
    @Autowired
    private ContentUpVoteTimesOperableCounter   contentUpVoteTimesOperableCounter;
    @Autowired
    private ContentDownVoteTimesOperableCounter contentDownVoteTimesOperableCounter;
    @Autowired
    private TransactionTemplate                 transactionTemplate;

    /**
     * @see ContentVoteService#vote(ContentVoteRequest)
     */
    @Override
    public BaseResult vote(ContentVoteRequest request) {
        // XXX 以后如果请求量大了走异步队列
        // Check request
        ServiceAssert.notBlank(request.getContentId(), Errors.Commons.REQUEST_PARAMETER_ERROR);
        ServiceAssert.notBlank(request.getUserId(), Errors.Commons.REQUEST_PARAMETER_ERROR);

        InfoUserVoteContentKey voteKey = new InfoUserVoteContentKey();
        voteKey.setUserId(request.getUserId());
        voteKey.setContentId(request.getContentId());
        InfoUserVoteContent userVote = infoUserVoteContentMapper.selectByPrimaryKey(voteKey);
        if (userVote != null) {
            return fail(com.fulihui.information.util.Errors.ContentVoteError.HAVE_VOTE);
        }

        boolean b = transactionTemplate.execute(status -> {
            // Insert into the mysql
            InfoUserVoteContent record = new InfoUserVoteContent();
            record.setContentId(request.getContentId());
            record.setUserId(request.getUserId());
            record.setVoteType(request.getVoteType());
            infoUserVoteContentMapper.insertSelective(record);

            // Increase the up vote
            UserContentOperate userContentOperate = new UserContentOperate();
            userContentOperate.setContentId(request.getContentId());
            if (EVoteType.UP.getCode().equals(request.getVoteType())) {
                contentUpVoteTimesOperableCounter.operate(userContentOperate);
            } else if (EVoteType.DOWN.getCode().equals(request.getVoteType())) {
                contentDownVoteTimesOperableCounter.operate(userContentOperate);
            }
            return true;
        });
        return b ? succ() : fail(Errors.Commons.SYSTEM_ERROR);
    }

    @Override
    public TSingleResult<String> querySingle(ContentVoteRequest request) {
        ServiceAssert.notBlank(request.getContentId(), Errors.Commons.REQUEST_PARAMETER_ERROR);
        ServiceAssert.notBlank(request.getUserId(), Errors.Commons.REQUEST_PARAMETER_ERROR);

        InfoUserVoteContentKey voteKey = new InfoUserVoteContentKey();
        voteKey.setUserId(request.getUserId());
        voteKey.setContentId(request.getContentId());
        InfoUserVoteContent userVote = infoUserVoteContentMapper.selectByPrimaryKey(voteKey);
        return succTSingle(userVote == null ? null : userVote.getVoteType());
    }

    /**
     * @see ContentVoteService#userVotes(ContentVoteRequest)
     */
    @Override
    public TPageResult<ContentListItemDTO> userVotes(ContentVoteRequest request) {
        // Check request
        ServiceAssert.notBlank(request.getUserId(), Errors.Commons.REQUEST_PARAMETER_ERROR);

        // The contents of the query the users vote
        InfoUserVoteContentExample voteExample = new InfoUserVoteContentExample();
        voteExample.createCriteria().andUserIdEqualTo(request.getUserId())
                .andVoteTypeEqualTo(request.getVoteType()); // XXX 以后有踩了需要换成in(...)查询
        voteExample.setOffset(request.start4Mysql());
        voteExample.setLimit(request.getRows());
        List<InfoUserVoteContent> userVotes = infoUserVoteContentMapper.selectByExample(voteExample);
        long totalCount = infoUserVoteContentMapper.countByExample(voteExample);

        // With the list of the content id queries
        List<ContentListItemDTO> contentListItems;
        if (!isEmpty(userVotes)) {
            List<String> contentIds = userVotes.stream()
                    .map(InfoUserVoteContent::getContentId)
                    .collect(Collectors.toList());
            contentListItems = contentRepository.queryItemListByIds(contentIds);
        } else {
            contentListItems = emptyList();
        }
        return succTPage(contentListItems, request.getPage(), request.getRows(), (int) totalCount);
    }
}
